#include <iostream>
#include "Object.hpp"
#include "Shader.hpp"
#include "Node.hpp"
#include "Fps.hpp"
#include "Texture.hpp"
#include "TexturePair.hpp"
#include "GL/glfw.h"

const int WIDTH = 1024, HEIGHT = 600;
bool FULLSCREEN = false;
float iterations = 5.0f;

float time_last = 0.0f;
int main()
{

	glfwInit();
	if( !glfwOpenWindow( WIDTH, HEIGHT, 8,8,8,8, 32,0, FULLSCREEN ? GLFW_FULLSCREEN : GLFW_WINDOW ) )
    {
		glfwTerminate();
		return 1;
    }

    glewInit();
	Init();
	//Shader::PassthroughShader = Shader("Shaders/PassthroughVertex.glsl", "Shaders/PassthroughFragment.glsl");
    ShaderProvider::SetGLSLVersion("410");

    //Shader PostShader("Shaders/PostVertex.glsl", "Shaders/PostFrag.glsl");


    //Shader PostShader("Shaders/PostVertex.glsl", "Shaders/PostFrag.glsl");

	Shader::UseNoShader();
    //Shader SimpleShader("Shaders/SimpleVertex.glsl", "Shaders/SimpleFrag.glsl");
	//SimpleShader.Use();
	
	//Shader PassShader("Shaders/PassthroughVertex.glsl", "Shaders/PassthroughFragment.glsl");
    //std::cin.get();

    Object SimpleMesh(Mesh::OBJ_MODE);
    SimpleMesh.LoadObj("Models/suzanne_highres.obj");
    
    
    SimpleMesh.SetShader(Shader::PhongShader);
    SimpleMesh.SetColor(Vector3(1.0, 0.3, 0.2));
    SimpleMesh.Update();

	Object NewMesh(Mesh::OBJ_MODE);
	NewMesh.LoadObj("Models/suzanne_highres.obj");
	NewMesh.SetShader(Shader::PhongShader);
	NewMesh.SetColor(Vector3(0.3, 1.0, 0.2));
	
	Object SimpleMesh2(Mesh::OBJ_MODE);
	SimpleMesh2.LoadObj("Models/suzanne_highres.obj");
	SimpleMesh2.SetShader(Shader::PhongShader);
	SimpleMesh2.SetColor(Vector3(0.2, 0.3, 1.0));
	
	Object CubeMesh(Mesh::OBJ_MODE);
	CubeMesh.LoadObj("Models/cube.obj");
	CubeMesh.SetShader(Shader::PhongShader);
	CubeMesh.SetColor(Vector3(0.5, 0.5, 0.5));
	
	Camera kamera;
	
	
    Node SimpleNode;
    SimpleNode.AttachCamera(&kamera);
    SimpleNode.AttachObject(&SimpleMesh);
    
    Node CubeNode;
    CubeNode.AttachCamera(&kamera);
    CubeNode.AttachObject(&CubeMesh);
    

    Node SimpleNode2;
    SimpleNode2.AttachCamera(&kamera);
	SimpleNode2.AttachObject(&NewMesh);
	
	Node SimpleNode3;
	SimpleNode3.AttachCamera(&kamera);
	SimpleNode3.AttachObject(&SimpleMesh2);
    Texture t(WIDTH,HEIGHT);
    Texture t2(WIDTH, HEIGHT);
    TexturePair tp(&t, WIDTH, HEIGHT);
    //Texture::Unbind();
	Texture Sharp(WIDTH, HEIGHT);
	Texture Final(WIDTH, HEIGHT);

    glfwSwapInterval(0);
    bool running = true;
    Fps fpsCounter;
    iterations = 18.0f;
    float BlurStrength = 0.25f;
    while(running)
    {
		
		if(glfwGetKey('+'))
		{
			
			iterations+= 0.01f;
			std::cout << iterations << std::endl;
		}
		if(glfwGetKey('-'))
		{
			iterations-= 0.01f;
			std::cout << iterations << std::endl;
		}
		
		if(glfwGetKey('T'))
		{
			
			BlurStrength+= 0.01f;
			std::cout << BlurStrength << std::endl;
		}
		if(glfwGetKey('Y'))
		{
			BlurStrength-= 0.01f;
			std::cout << BlurStrength << std::endl;
		}
		
		if(glfwGetKey(GLFW_KEY_RIGHT))
		{
			kamera.TurnX(-0.01f);
		}
		if(glfwGetKey(GLFW_KEY_LEFT))
		{
			kamera.TurnX(0.01f);
		}
		if(glfwGetKey(GLFW_KEY_UP))
		{
			kamera.TurnY(0.01f);
		}
		if(glfwGetKey(GLFW_KEY_DOWN))
		{
			kamera.TurnY(-0.01f);
		}
		
		if(glfwGetKey('W'))
		{
			kamera.Move(0.05f);
		}
		if(glfwGetKey('S'))
		{
			kamera.Move(-0.05f);
		}
		
		Shader::PhongShader -> UpdateUniform("FocalDistance", iterations);
		Shader::PhongShader -> UpdateUniform("BlurStrength", BlurStrength);
		//Shader::HorizontalGauss -> UpdateUniform("FocalDistance", iterations);
		//Shader::VerticalGauss -> UpdateUniform("FocalDistance", iterations);
		
        tp.GetTexture().RenderTo();
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		if(glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam( GLFW_OPENED ))
			running = false;
			
		
		CubeNode.Scale(10.0f);
		CubeNode.DrawAll();
		
		SimpleNode.Rotate(180.0f, 1);
		SimpleNode.Rotate((glfwGetTime()) * 100.0f, 1);
		SimpleNode.Translate(Vector3(1.5f, 0.0f, 5.0f));
		SimpleNode.DrawAll();
		
		
		SimpleNode3.Rotate(180.0f, 1);
		SimpleNode3.Rotate((glfwGetTime()) * 100.0f, 3);
		SimpleNode3.Rotate((glfwGetTime()) * 50.0f, 1);
		
		SimpleNode3.Translate(Vector3(-0.5f, 0.0f, 2.5f));
		SimpleNode3.DrawAll();
		
		SimpleNode2.Rotate((glfwGetTime()) * 105.0f, 1);
		SimpleNode2.Rotate((glfwGetTime()) * 15.0f, 2);
		SimpleNode2.Rotate(180.0f, 1);
		SimpleNode2.Translate(Vector3(-1.5f, 0.0f, 0.0f));
		SimpleNode2.DrawAll();

        //t.RenderToTexture(PostShader, t2);
        //t2.RenderToTexture(PostShader, t);
		tp.GetTexture().CopyToTexture(Sharp);
        
        tp.RenderPass(*Shader::VerticalGauss, 3);
        tp.RenderPass(*Shader::HorizontalGauss, 3);
        
        //tp.RenderPass(*Shader::SimpleHorizGauss, 25);
        //tp.RenderPass(*Shader::SimpleVertGauss, 25);
        Texture::Blend(Sharp, tp.GetTexture(), Final, *Shader::BlendShader);
        
        //tp.RenderPass(*Shader::HorizontalGauss, 1);
        //tp.RenderPass(*Shader::VerticalGauss, 1);
        //Final.RenderToScreen();
        tp.GetTexture().RenderToScreen();
        //tp.GetTexture().RenderToScreen();
        //Sharp.RenderToScreen();
        //t.RenderToScreen(PostShader);

		fpsCounter.printFps();
		glfwSwapBuffers();


	}

    glfwTerminate();

}
